package com.blue.base.redis.bean;

import com.blue.base.redis.executors.LockExecutor;
import com.blue.base.redis.utils.HostUtil;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;


/**
 * 锁模板方法
 *
 * @author liulei
 * @version 1.0
 */
@Slf4j
public class LockTemplate {

    private static final String PROCESS_ID = HostUtil.getLocalMAC() + HostUtil.getJvmPid();

    @Setter
    private LockExecutor lockExecutor;

    /**
     * 加锁,获取锁的时间超过注解设置的时间，自动退出
     *
     * @param key     加锁key
     * @param expire  key过期时间[毫秒]
     * @param timeout 自旋时间[毫秒 获取不到时，while循环获取锁的时间]
     */
    public RedisLockInfo lock(String key, long expire, long timeout) throws Exception {
        Assert.isTrue(timeout > 0, "tryTimeout must more than 0");
        long start = System.currentTimeMillis();
        int acquireCount = 0;
        String value = PROCESS_ID + Thread.currentThread().getId();
        while (System.currentTimeMillis() - start < timeout) {
            boolean result = lockExecutor.acquire(key, value, expire);
            acquireCount++;
            if (result) {
                return new RedisLockInfo(key, value, expire, timeout, acquireCount);
            }
            Thread.sleep(50);
        }
        // 获取锁失败，如果需要中止程序运行，务必要调用此方法后做后续操作，参考@see com.blue.base.redis.aop.LockInterceptor.invoke()方法使用规范
        log.info("规定时间[{}]内获取锁失败", timeout);
        return null;
    }

    /**
     * 释放锁
     */
    public boolean releaseLock(RedisLockInfo redisLockInfo) {
        return lockExecutor.releaseLock(redisLockInfo);
    }
}
